# Hackware Web Services Payment

## Overview

Pay through various payment gateways.

## Main goals

- Web API with RESTful JSON responses.
- Pay through offsite payment gateways.
- Notify payment to custom HTTP service (such as the wallet API).

## Features

- As consumer I can perform a payment.
- As consumer I can choose to pay with the Khipu, Flow, DLocalGo and PayPal payment gateways.
- As system I can receive payment notifications from offsite payment gateways so that a payment is confirmed.
- As system I can send a notification to a custom HTTP service so that a payment gets processed on that end.

## Routes

- `GET /gateways/` list of available gateways
- `GET /gateways/payment-methods/${schema=purchase}` list of all payment
  methods, incluiding `gateway` and `property` (which indicates the field that
  selects payment method remotely)
- `GET /gateways/{gateway}/schemas/${schema=purchase}` fields required for schema
- `POST /gateways/{gateway}/purchase` pay something
- `POST /gateways/{gateway}/notify` IPN
- `POST /payments/{uuid}` payment status

### Standard payment provider properties on purchase schemas

Different payment providers will require you to send different parameters. In
order to make its conversion a no-brainer for HTTP consumers, common fields have
an standard name that will be translated to the proper property name for a
specific provider, and set and as a readOnly default value when you request a
purchase schema and send these as query params.

- subject
- email
- due_amount
- payment_method
- currency

A request example:

```
GET /gateways/khipu/schemas/purchase?email=hello@example.org&due_amount=10000

> ...
> "properties": {
>   ...
>   "amount": {
>     "title": "Monto",
>     "type": "number",
>     "multipleOf": 1,
>     "default": 10000,
>     "readOnly": true
>   },
>   "payer_email": {
>     "title": "Email",
>     "type": "string",
>     "format": "idn-email",
>     "default": "hello@example.com",
>     "readOnly": true
>   },
>   ...
>}
```

Additionally, you can always set a `return_url` query param parameter when you
`POST /gateways/{gateway}/purchase` in order to dynamically set the url to
return the user after he has paid or cancelled the payment (overriding
`config('payment.return_url')`, a `uuid` query param will be appended to this
url so you can verify its status. The reasoning for not including this field in
the schema is because it's never a user-set field.

## Models

### Configuration based

- gateways:
  - class: full class name (incluiding namespace) for this gateway.
  - test_mode: optional (depends on the gateway), test mode switch.
  - credentials: credential that your class uses, use environment variables for this.
  - payment_methods: payment methods property name for each schema, used to list available payment methods for all available gateways.
  - schemas: an associative array with valid JSON Schemas, each schema represents a form displayed to the final user containing data to send to the payment gateway (or exceptionally required by the processing payment method).

### Database based

- payments: uuid, user_uid, gateway, currency, amount, description, detail, status

## Run it

### Requirements

- [Hawese Core](https://git.hackware.cl/hawese-core/)

### Installation

```
composer require hackware/hawese-payment
```

#### Setup notifications

This package will trigger a request to an external service automattically after reception of an Instant Payment Notification (IPN) from a payment gateway, take it as an external IPN which triggers an internal IPN (I think this is actually very handy :P).

To configure it you will need to change the `config/payment.php` `notify_to` field. It's configured to work with [hackware/hawese-wallet](https://git.hackware.cl/hawese-wallet) by default, but it will work with any other endpoint if configured properly.

There's nothing cryptic about it. In the `params` associative array setup your endpoint input fields as keys and payment attributes with the format `payment.payment_model_attribute` as values (or actually any other string `payment.` is used as keyword for the associated Payment model instance).

#### Environment variables

- `KHIPU_RECEIVER_ID` credentials.
- `KHIPU_SECRET_KEY` credentials.
- `FLOW_API_KEY` credentials.
- `FLOW_SECRET_KEY` credentials.
- `FLOW_TEST_MODE` test mode switch, boolean.
- `DLOCALGO_API_KEY` credentials.
- `DLOCALGO_SECRET_KEY` credentials.
- `DLOCALGO_TEST_MODE` test mode switch, boolean.
- `DLOCALGO_COUNTRIES` enabled countries list, separated by spaces.
- `PAYPAL_CLIENT_ID` credentials.
- `PAYPAL_SECRET_KEY` credentials.
- `PAYPAL_TEST_MODE` test (sandbox) mode switch, boolean.
- `PAYMENT_SOURCE_URL` is the place where to download the source code of your version of this project. Required.
- `PAYMENT_WALLET_ENDPOINT` endpoint to a running [hackware/hawese-wallet](https://git.hackware.cl/hawese-wallet) instance for IPN.
- `PAYMENT_RETURN_URL` where to return the payer after a successful or failed payment, an `uuid` query param will be appended to this URL, so you can call to the `payments.verify` route from that endpoint. [hackware/userland](https://git.hackware.cl/userland) is already prepared for that on the `/add-funds/verify` endpoint.
- `PAYMENT_CORE_AUTH_TOKEN` system token in key:secret format. It's returned by the [hackware/hawese](https://git.hackware.cl/hawese) `composer run-script seed` command, which runs the initial [hackware/hawese-seeds](https://git.hackware.cl/hawese-seeds).

## Contributions

If you want to create a custom gateway please contact me first for guidelines, otherwise your contribution might be rejected (and implementation will be harder to grasp).

## Error codes

- 2001. `UnexpectedResponseException`: Unexpected HTTP response.
- 2002. `UnexpectedValueException`: Unsupported request method.
- 2999. `LogicException`: Exclusive to `getBodyOrQueryParams`, POST & GET parameters in the same request. Write this logic yourself.

## Copyright and licensing

Copyright 2019-2022 [Hackware SpA](https://hackware.cl).

This project is licensed under the GNU Affero General Public License v3 or any later version.

### How to comply with license terms?

To comply with license terms you must provide the means to access the source code of your version of the software easily and free of charge to any person that has access to the software, even users which access through a network (i.e. web browser). I've provided an easy way to accomplish this requirement by setting the `PAYMENT_SOURCE_URL` environment variable, this will show the link on the index page (/) under the JSON `links.payment_sourcecode` property.

Any modification or inclusion of this source code will inherit the same license, that is, it can't be sublicensed. But since it's a REST API you can consume it with any other software. That means that this software must always respect users freedom, even if the HTTP API is consumed by a privative one.

### Other licensing options

If you want to use the software but are afraid of or can't comply with the license terms we can arrange other license terms for your case. Though most probably I'll not accept if you don't provide your modifications to the software back.
